package net.vistiyos.search;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import net.vistiyos.model.Hit;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class searchs {
	
	/**
	 * 
	 * @param key The API key.
	 * @param query The query string,that you want to search.
	 * @return The number of pages of the query.
	 * @throws MalformedURLException Ocurred if the api change. 
	 * @throws IOException Ocurred if exists any error of connection. 
	 * @throws SAXException Ocurred if the api change.
	 */
	public static int getNumPages(String key,String query) throws MalformedURLException, IOException, SAXException{
		String url="http://api.filestube.com/?key="+key+"&phrase="+query;
		String response=getResponseURL(url);
		return getTotalResults(response)/10;
	}
	
	/**
	 * 
	 * @param key the API key
	 * @param query The query string,that you want to search.
	 * @param page The page of the results that you want to get.
	 * @return An ArrayList of Hit -> View the Hit documentation.
	 * @throws MalformedURLException Ocurred if the api change. 
	 * @throws IOException Ocurred if exists any error of connection.
	 * @throws SAXException Ocurred if the api change.
	 * @throws ParseException Ocurred if the api change.
	 */
	static public ArrayList<Hit> searchByPage(String key,String query,int page) throws MalformedURLException, IOException, SAXException, ParseException{
		String url="http://api.filestube.com/?key="+key+"&phrase="+query+"&page="+page;
		String response=getResponseURL(url);
		return parserXML(response,new ArrayList<Hit>());
	}
	
	/**
	 * 
	 * @param key the API key
	 * @param query The query string,that you want to search.
	 * @param extension The extension of the file that you want to search.
	 * @param page The page of the results that you want to get.
	 * @return An ArrayList of Hit -> View the Hit documentation.
	 * @throws MalformedURLException Ocurred if the api change.
	 * @throws IOException Ocurred if exists any error of connection.
	 * @throws SAXException Ocurred if the api change.
	 * @throws ParseException Ocurred if the api change.
	 */
	static public ArrayList<Hit> searchByExtensionByPage(String key,String query,String extension,int page) throws MalformedURLException, IOException, SAXException, ParseException{
		String url="http://api.filestube.com/?key="+key+"&phrase="+query+"&extension="+extension+"&page="+page;
		String response=getResponseURL(url);
		return parserXML(response,new ArrayList<Hit>());
	}
	
	/**
	 * 
	 * @param URL The URL that you want to get the response.
	 * @return A String representation of the response.
	 * @throws MalformedURLException Ocurred if the api change.
	 * @throws IOException Ocurred if exists any error of connection.
	 */
	static private String getResponseURL(String URL) throws MalformedURLException, IOException{
		URLConnection urlc=new URL(URL).openConnection();
		Writer writer=new StringWriter();
		InputStream in=urlc.getInputStream();
		if(in!=null){
			char [] buffer=new char[1024];
			try{
				Reader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
				int n;
				while ((n = reader.read(buffer)) != -1) {
					writer.write(buffer, 0, n);
				}
			}finally{
				in.close();
			}
		}
		return writer.toString();
	}
	
	/**
	 * 
	 * @param xml A String representation of the xml file.
	 * @param data An ArrayList<Hit> to add new elements.
	 * @return An ArrayList<Hit> result of mixed data and the new elements.
	 * @throws SAXException
	 * @throws IOException Ocurred if exists any error of connection.
	 * @throws ParseException
	 */
	static private ArrayList<Hit> parserXML(String xml,ArrayList<Hit> data) throws SAXException, IOException, ParseException{
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		 try {
		        DocumentBuilder db = dbf.newDocumentBuilder();
		        ByteArrayInputStream xmlStream = new ByteArrayInputStream(xml.getBytes());
		        InputSource in=new InputSource(xmlStream);
		        Document dom = db.parse(in);
		        Element raiz=dom.getDocumentElement();
		        NodeList nodes=raiz.getElementsByTagName("hits");
		        for(int i=0;i<nodes.getLength();i++){
		        	Map<String,String> attributes=new HashMap<String,String>();
		        	Node aux=nodes.item(i);
		        	attributes.put("id", aux.getAttributes().item(0).getTextContent());
		        	NodeList hijos=aux.getChildNodes();
		        	for(int j=0;j<hijos.getLength();j++){
		        		Node aux2=hijos.item(j);
		        		attributes.put(aux2.getNodeName(), aux2.getTextContent());
		        	}
		        	Hit hit=new Hit(attributes);
		        	data.add(hit);
		        }
		    } catch (ParserConfigurationException pce) {
		    	System.out.println(pce.getMessage());
		    }
		 return data;
	}
	
	/**
	 * 
	 * @param xml
	 * @return
	 * @throws SAXException
	 * @throws IOException
	 */
	static private int getTotalResults(String xml) throws SAXException, IOException{
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		 try {
		        DocumentBuilder db = dbf.newDocumentBuilder();
		        ByteArrayInputStream xmlStream = new ByteArrayInputStream(xml.getBytes());
		        InputSource in=new InputSource(xmlStream);
		        Document dom = db.parse(in);
		        Element raiz=dom.getDocumentElement();
		        NodeList nodes=raiz.getElementsByTagName("hitsTotal");
		        return Integer.parseInt(nodes.item(0).getTextContent());
		 } catch (ParserConfigurationException pce) {
		    	System.err.println(pce.getMessage());
		 }
		 return 0;
	}

}
